function Scroller(width, height, originalPosition) {
    this.canvas = document.createElement("canvas");
    this.canvas.width = width;
    this.canvas.height = height;
    this.context = this.canvas.getContext("2d");
    this.texture = gl.createTexture();
    this.originalPosition = originalPosition;
    this.totalPixelsCopied = 0;
    this.position = 0;
    this.currentPosition = 0;
    this.lastTime = 0;
    this.offset = 0;
    //document.body.appendChild(document.createElement("div"));
    //document.body.appendChild(this.canvas);
}
Scroller.prototype.setPosition = function(units) {
    this.position += units;
    this.offset = this.offset - units;
}
//Prepare scroller canvas from sections of other canvases.
Scroller.prototype.prepareCanvas = function() {
    var canvas = canvases[canvasIndex],	    
	context2D = canvas.getContext("2d"),
	difference = scroller.width - this.totalPixelsCopied,
	pixelsCopied = 0,
	imageData;

    //Content that remains to be shown is shorter than the scroller.
    if ((canvas.width - currentCanvasPosition) < difference) {		    
	imageData = context2D.getImageData(currentCanvasPosition, 0, canvas.width - currentCanvasPosition, canvas.height);
	pixelsCopied = canvas.width - currentCanvasPosition;
	this.totalPixelsCopied += pixelsCopied;
	currentCanvasPosition = 0;
	canvasIndex++;		    
	
	if (canvasIndex >= canvases.length) {
	    canvasIndex = 0;
	}		    
    }
    else {
	imageData = context2D.getImageData(currentCanvasPosition, 0, difference, canvas.height);
	pixelsCopied = difference;
	currentCanvasPosition += difference + 1;
	this.totalPixelsCopied += difference;
    }

    //Use putImageData() to paint the pixel data into the context.
    this.context.putImageData(imageData, this.currentPosition, 0);
    this.currentPosition = this.currentPosition + pixelsCopied;
    
    if (this.totalPixelsCopied < scroller.width) {
	this.prepareCanvas(currentCanvasPosition);
    }
    else {
	this.totalPixelsCopied = 0;
	this.currentPosition = 0;
    }
}
Scroller.prototype.createTextureFromCanvas = function() {
    //Tell WebGL which texture we are working on (WebGL operates on one texture at a time).
    gl.bindTexture(gl.TEXTURE_2D, this.texture);
    
    //Flip text.
    gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
    
    //Upload our canvas into the texture object in the graphics card.
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.canvas);
    
    //specify how our image is going to be mapped onto the texture object
    //WebGL works supercool with images that have width and height a power of two (POT) - it knows how to scale them
    //For the other case (non-POT), we simply say "Just WRAP the texture object without thinking"	    
    if (isPowerOfTwo(this.canvas.width) && isPowerOfTwo(this.canvas.height)) {
	//gl.NEAREST means when the texture is being scaled up and when it's being scaled down, WebGL should use a filter
	//that determines the colour of a given point just by looking for the nearest point in the original image.
	gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
	gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
    }
    else {
	//Textures that are non-power-of-two (NPOT) do not render unless texture filtering is set
	//so it does not require mips, and texture wrapping is set to CLAMP_TO_EDGE. 
	gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);	//Turn off the need for mips.
	gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
	gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
    } 
    
    gl.bindTexture(gl.TEXTURE_2D, null);
}
Scroller.prototype.draw = function(mouseDown, isStopped) {
    if (!mouseDown && !isStopped) {
	this.position = this.originalPosition - this.offset;	//When this is >= -2, it's off-screen.
	
	//Texture has scrolled off-screen.
	if (this.position <= -4) {
	    //Leave it but add new to end?
	    this.offset = 0;
	    this.originalPosition = 2;
	    this.position = this.originalPosition - this.offset;
	    this.prepareCanvas();
	    this.createTextureFromCanvas();
	}
    }
    
    mat4.identity(mvMatrix);
    mat4.identity(pMatrix);	//Orthographic projection matrix.
    
    mvPushMatrix();
    mat4.translate(mvMatrix, [this.position, 0.0, 0.0]);
    
    gl.bindTexture(gl.TEXTURE_2D, this.texture);
    
    gl.bindBuffer(gl.ARRAY_BUFFER, verticesBuffer);
    gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, verticesBuffer.itemSize, gl.FLOAT, false, 0, 0);
    
    gl.bindBuffer(gl.ARRAY_BUFFER, vertexTextureCoordBuffer);
    gl.vertexAttribPointer(shaderProgram.textureCoordAttribute, vertexTextureCoordBuffer.itemSize, gl.FLOAT, false, 0, 0);
    
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, vertexIndexBuffer);
    
    setMatrixUniforms(shaderProgram, pMatrix, mvMatrix);
    gl.drawElements(gl.TRIANGLES, vertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0);
    
    mvPopMatrix();
    gl.bindTexture(gl.TEXTURE_2D, null);
}
Scroller.prototype.animate = function(mouseDown, isStopped) {
    var timeNow = new Date().getTime();
	    
    if (this.lastTime != 0) {
	var elapsed = timeNow - this.lastTime;
	
	if (!mouseDown && !isStopped) {
	    this.offset += elapsed / 5000.0;
	}
    }
    
    this.lastTime = timeNow;
}